#include <scdl/parser/StringMap.hpp>
#include <scdl/parser/Symbol.hpp>

#include <cstring>
#include <cstdlib>
#include <iostream>

using std::cout;
using namespace scdl;

namespace scdl {
        static const int NR_SLOTS = 997;
        static const StringMapData DEFAULT_DATA = 0;

        struct StringMapSlot {
                char *index;
                StringMapData data;
                StringMapSlot *next;
                StringMapSlot *nextInserted;
        };
}


StringMap::StringMap()
        : first(0), prev(0)
{
        slots = new StringMapSlot*[NR_SLOTS];
        memset(slots, 0, sizeof(StringMapSlot*) * NR_SLOTS);
}

StringMap::~StringMap()
{
        clear();
}

void StringMap::clear()
{
        StringMapSlot *cur, *next;
        for (int i = 0; i < NR_SLOTS; i++) {
                cur = slots[i];
                while (cur != 0) {
                        next = cur->next;
                        free(cur->index);
                        if (cur->data)
                                cur->data->unref();
                        delete cur;
                        cur = next;
                }
                slots[i] = 0;
        }
}

void StringMap::print()
{
        StringMapSlot *cur = first;
        while(cur) {
                cur->data->prettyPrint(true);
                cout << "\n";
                cur = cur->nextInserted;
        }
}

void StringMap::clearPrintChain()
{
        first = prev = 0;
}

StringMapData &StringMap::operator[](const char *idx)
{
        StringMapSlot **head = slots + hash(idx), *slot = *head;
        while (slot != 0 && strcmp(slot->index, idx) != 0)
                slot = slot->next;

        if (slot == 0) {
                slot = new StringMapSlot;
                slot->index = strdup(idx);
                slot->data = DEFAULT_DATA;
                slot->next = *head;
                slot->nextInserted = 0;
                if (prev)
                        prev->nextInserted = slot;
                else
                        first = slot;
                prev = slot;
                *head = slot;
        }

        return slot->data;
}

bool StringMap::find(const char *idx)
{
        StringMapSlot **head = slots + hash(idx), *slot = *head;
        while (slot != 0 && strcmp(slot->index, idx) != 0)
                slot = slot->next;
        return (slot != 0);
}

int StringMap::hash(const char *str)
{
        int hashed = 0;
        for (int i = 0; str[i] != '\0'; i ++)
                hashed += str[i] * (i+1) - 30;
        hashed %= NR_SLOTS;
        return hashed;
}
